Enterprise Objects Framework Release 1.1 Copyright ã1995 by NeXT Computer, Inc.  All Rights Reserved.

EORelationship

Inherits From:	NSObject

Declared In:	eoaccess/EORelationship.h

Class Description

An EORelationship describes a relationship from one EOEntity to another, based on attributes of the two entities. By defining EORelationships in your application's EOModel, you can cause the relationships defined in the database to be automatically resolved as enterprise objects are fetched. For example, an Employee entity may contain its department ID as an attribute, but without an EORelationship this will only appear in an employee enterprise object as a number. With an EORelationship explicitly connecting the Employee entity to the Department entity, an employee enterprise object will automatically be given its department enterprise object when an EODatabaseChannel fetches it from the database.

You usually define relationships in your EOModel with the EOModeler application, which is documented in the Enterprise Objects Framework Developer's Guide, Chapter 5, ªUsing EOModeler.º EORelationships are primarily for use by the Enterprise Objects Framework; unless you have special needs you shouldn't need to access them in your application's code.

A relationship is directional: One entity is considered the source, and the other is considered the destination. The relationship belongs to the source entity, and may only be traversed from source to destination. To simulate a two-way relationship you have to create an EORelationship for each direction.

Most relationships simply relate the objects of one entity to those of another by comparing attribute values between them. Such a relationship must be defined as to-one or to-many based on how many objects of the destination match each object of the source. This is called the cardinality of the relationship. In a to-one relationship, there must be exactly one destination object for each source object; in a to-many relationship there can be any number of destination objects for each source object. See ªCreating a Simple Relationshipº below for more information.

A chain of relationships across several entities can be flattened, creating a single relationship that spans them all. For example, a relationship between employees and departments and a relationship between departments and facilities can be flattened into a relationship going directly from employees to facilities. A flattened relationship is determined to be to-many or to-one based on the relationships it spans; if all are to-one, then the flattened relationship is to-one, but if any of them is to-many the flattened relationship is to-many. See ªCreating a Flattened Relationshipº below for more information.

Like the other major modeling classes, EORelationship provides a user dictionary for the application to store any auxiliary information it needs.

Creating a Simple Relationship

A simple relationship is defined by the attributes it compares in connecting its source and destination entities. Each source-destination pair of attributes is encapsulated in an EOJoin object, which also defines the way that the attributes should be compared and how the relationship should be evaluated. For example, to create a relationship from the Employee entity to the Department entity, a join has to be created from the deptID attribute of the Employee entity to the same attribute of the Department entity). The values of these two attributes must be equal for a match to result. Note that deptID is the primary key attribute for the Department entity, so there can only be one department per employee; this relationship is therefore to-one.

This code excerpt creates an EORelationship for the relationship described above and adds it to the EOEntity for the Employee entity:

EOEntity *employeeEntity;      /* Assume this exists. */
EOEntity *deptEntity;          /* Assume this exists. */
EOAttribute *empDeptIDAttribute;
EOAttribute *deptIDAttribute;
EOJoin *toDeptJoin;
EORelationship *toDeptRelationship;

empDeptIDAttribute = [employeeEntity attributeNamed:@"deptID"];
deptIDAttribute = [deptEntity attributeNamed:@"deptID"];

toDeptJoin = [[[EOJoin alloc]
    initWithSourceAttribute:empDeptIDAttribute
    destinationAttribute:deptIDAttribute
    joinOperatior:EOJoinEqualTo
    joinSemantic:EOInnerJoin] autorelease];

toDeptRelationship = [[[EORelationship alloc]
    initWithName:@"toDepartment"]] autorelease];
[toDeptRelationship addJoin:toDeptJoin];
[toDeptRelationship setToMany:NO];

[employeeEntity addRelationship:toDeptRelationship];

This code first gets the attributes from the source and destination entities, and then creates an EOJoin with them. EOJoinEqualTo indicates that the values of the attributes must be equal for a match, and EOInnerJoin indicates that only objects that actually have a matching destination object will be included in the result when the relationship is traversed. Next, a new EORelationship is created, the EOJoin is added to it, and it's set as to-one. employeeEntity is then assigned the new EORelationship.

Creating a to-many relationship in the opposite direction merely swaps the source and destination attributes, and assigns the relationship to the EOEntity for the Department entity:

EOJoin *toEmployeesJoin;
EORelationship *toEmployeesRelationship;

toEmployeesJoin = [[[EOJoin alloc]
    initWithSourceAttribute:deptIDAttribute
    destinationAttribute:empDeptIDAttribute
    joinOperatior:EOJoinEqualTo
    joinSemantic:EOInnerJoin] autorelease];

toEmployeesRelationship = [[[EORelationship alloc]
    initWithName:@"toDepartment"] autorelease];
[toEmployeesRelationship addJoin:toEmployeesJoin];
[toEmployeesRelationship setToMany:YES];

[deptEntity addRelationship:toEmployeesRelationship];

Note that this relationship is to-many precisely because the destination attribute isn't the primary key for its entity (Employee), and therefore isn't unique with regard to that entity.

A relationship isn't restricted to only one EOJoin. It's entirely possible for a relationship to be defined based on two or more attributes in the source and destination entities. For example, if the employees database contains a picture of each employee identified by first and last name (a contrived example, to be sure), you define the relationship by joining each of the first and last names in the Employee entity to the same attribute in the EmpPhoto attribute.

A simple relationship is considered to reference all of the attributes in its joins. You can use the referencesProperty: method to find out if an EORelationship references a particular attribute.

Creating a Flattened Relationship

A flattened relationship depends on several simple relationships already existing. Assuming that several do exist, creating a flattened relationship is straightforward. Suppose that, in addition to the toDepartment relationship used above, the Department entity has a relationship to its facility (building)Ðthe toFacility relationship. This code excerpt creates a flattened relationship directly from Employee to each employee's facility:

EOEntity *employeeEntity;      /* Assume this exists. */
EORelationship *toFacilityRelationship;

toFacilityRelationship = [[EORelationship alloc]
    initWithName:@"toFacility"];
[toFacilityRelationship setEntity:employeeEntity];
[toFacilityRelationship setDefinition:@"toDepartment.toFacility"];

[employeeEntity addRelationship:toFacilityRelationship];

All that's needed to establish the relationship is a data path (also called the definition) naming each component relationship connected, with the names separated by periods. Note that because the cardinality of a flattened relationship is determinable from its components, no setToMany: message is required here.

A simple relationship is considered to reference all of the relationships in its definition, plus every attribute referenced by the component relationships. You can use the referencesProperty: method to find out if an EORelationship references another relationship or attribute.

Instance Variables

None declared in this class.

Method Types

Initializing instances	- initWithName:

Setting the name	- setName:
- name
+ isValidName:

Using joins	- addJoin:
- removeJoin:
- joins

Getting attributes joined on	- sourceAttributes
- destinationAttributes

Getting the definition	- componentRelationships
- setDefinition:
- definition

Getting the entities joined	- setEntity:
- entity
- destinationEntity

Checking type	- isCompound
- isFlattened

Setting to-many	- setToMany:
- isToMany

Checking references	- referencesProperty:

Setting the user dictionary	- setUserDictionary:
- userDictionary

Class Methods

isValidName

+ (BOOL)isValidName:(NSString *)name

Returns YES if name is a legal name for a relationship, NO otherwise. This method merely sends isValidName: to the EOEntity class with name as the argument.

Instance Methods

addJoin:

- (BOOL)addJoin:(EOJoin *)aJoin

Adds a source-destination attribute pair to the relationship. Returns YES if successful, NO if either of aJoin's attributes already belongs to another join of the relationship or if the relationship is flattened.

See also:  - joins, - isFlattened, - setDefinition:

componentRelationships

- (NSArray *)componentRelationships

Returns the array of sub-relationships that make up a flattened relationship, or nil if the relationship is not flattened.

definition

- (NSString *)definition

Returns the data path of a flattened relationship; for example ªtoDepartment.toFacilityº. If the relationship isn't flattened, returns nil.

destinationAttributes

- (NSArray *)destinationAttributes

Returns the destination EOAttributes of a simple (nonflattened) relationship. These correspond one-to-one with the attributes returned by sourceAttributes. Returns nil if the relationship is flattened.

See also:  - joins

destinationEntity

- (EOEntity *)destinationEntity

Returns the relationship's destination entity, which is determined by the destination entity of its joins for a simple relationship, and by whatever ends the data path for a flattened relationship. For example, if a flattened relationship's definition is ªtoDepartment.toFacilityº the destination entity is the Facility entity.

See also:  - entity

entity

- (EOEntity *)entity

Returns the relationship's source entity.

See also:  - destinationEntity, - addRelationship: (EOEntity)

initWithName:

- initWithName:(NSString *)name

Initializes a newly allocated EORelationship with name as its name. The EORelationship needs to have at least one join or a definition before it's usable. This is the designated initializer for the EORelationship class. Returns self.

isCompound

- (BOOL)isCompound

Returns YES if the relationship has more than one join (that is, if it joins more than one pair of attributes), NO if it has only one join or is a flattened relationship. See ªCreating a Simple Relationshipº in the class description for information on compound relationships.

isFlattened

- (BOOL)isFlattened

Returns YES if the relationship traverses more than two entities, NO otherwise. See ªCreating a Flattened Relationshipº in the class description for an example of a flattened relationship.

isToMany

- (BOOL)isToMany

Returns YES if the relationship is to-many, NO if it's to-one.

See also:  - setToMany:

joins

- (NSArray *)joins

Returns all joins used by the relationship, or nil if the relationship is flattened.

See also:  - sourceAttributes, - destinationAttributes

name

- (NSString *)name

Returns the relationship's name.

referencesProperty:

- (BOOL)referencesProperty:aProperty

Returns YES if aProperty is an EORelationship in the relationship's data path or is an EOAttribute belonging to one of the relationship's joins, NO otherwise. See the class description for information of how relationships reference properties.

See also:  - referencesProperty: (EOEntity)

removeJoin:

- (void)removeJoin:(EOJoin *)aJoin

Deletes aJoin from the relationship. Does nothing if the relationship is flattened.

setDefinition:

- (void)setDefinition:(NSString *)definition

Changes the relationship to a flattened relationship by releasing all of its joins and setting definition as its data path; for example ªtoDepartment.toFacilityº. If the relationship doesn't have an entity, this method does nothing. See ªCreating a Flattened Relationshipº in the class description for more information on flattened relationships.

See also:  - setEntity:

setEntity:

- (void)setEntity:(EOEntity *)anEntity

Sets the entity of the relationship to anEntity. You only need to use this method when creating a flattened relationship; use EOEntity's addRelationship: to associate an existing relationship with an entity.

See also:  - setDefinition:

setName:

- (BOOL)setName:(NSString *)name

Sets the relationship's name to name. Returns YES if successful, NO if name is already in use by another attribute or relationship of the same entity.

setToMany:

- (BOOL)setToMany:(BOOL)flag

Sets a simple relationship as to-many according to flag, and returns YES. Does nothing and returns NO if the receiver is flattened. See the class description for considerations in setting this flag.

See also:  - isFlattened

setUserDictionary:

- (void)setUserDictionary:(NSDictionary *)aDictionary

Sets the dictionary of auxiliary data, which your application can use for whatever it needs. aDictionary must be a property list (that is, it must contain only NSString, NSData, NSArray, and NSDictionary objects).

sourceAttributes

- (NSArray *)sourceAttributes

Returns the source EOAttributes of a simple (nonflattened) relationship. These correspond one-to-one with the attributes returned by destinationAttributes. Returns nil if the relationship is flattened.

See also:  - joins

userDictionary

- (NSDictionary *)userDictionary

Returns a dictionary of user data. Your application can use this data for whatever it needs. This dictionary is a property list (that is, it contains only NSString, NSData, NSArray, and NSDictionary objects).